// X86Translator.h
// Defines the class X86Translator
#ifndef X86TRANSLATOR_H
#define X86TRANSLATOR_H

#include "crossbit/common.h"
#include "crossbit/Translator.h"
#include "crossbit/RegAllocator.h"
#include "arch/ia32/IA32ProcessorState.h"
#include <map>
#include <set>
#include <deque>
#include <vector>

namespace crossbit {

		class TBlock;
		class VInst;

		class X86Translator : public Translator {
				public:
						const static int CACHE_SIZE = 1024;

						X86Translator(IA32ProcessorState *state, RegAllocator *alloc);
						~X86Translator();

						// maybe don't need this function now
						// TBlock * headBlock();

						void setRegAllocator(RegAllocator * allocator)
						{
								reg_allocator = allocator;
						}

						void encode(VBlock *vb, TBlock *tb);

#if 0
						void setContextReturn(void *ret) 
						{
								GLOBAL::return_address = (XTMemAddr)ret;
						}
#endif

						inline void setFirstTime()
						{
								this->first_time = true;
						}


						static struct RegisterFile {
								XTInt32 eax;
								XTInt32 ecx;
								XTInt32 edx;
								XTInt32 ebx;
								XTInt32 ebp;
								XTInt32 esp;
								XTInt32 esi;
								XTInt32 edi;
						} saved;

				private:
						void initTranslation();
      IA32ProcessorState *src_state;
						VBlock *vblock;
						TBlock *tblock;

						bool first_time;
						bool dirty_esp;
						XTInt32 saved_esp;

						// the Translator should hold a pointer of reg allocator
						RegAllocator* reg_allocator;


						// =========================================================
						// Wrapper functions of reg allocator, since allocator may 
						// use ESP, and the X86Translator should deal with it.
						XTRegNum X86RegAlloc(XTRegNum vreg, RegAccessMode mode);
						XTRegNum X86RegAllocForce(XTRegNum vreg, XTRegNum expect, RegAccessMode mode);
						XTRegNum X86RegAllocForceExcept(XTRegNum vreg, XTRegNum except, RegAccessMode mode);
						void X86RegAllocReserve(XTRegNum treg);
						void X86RegAllocRelease(XTRegNum treg);


						// =========================================================
						//	    Exits Related

						void setBlockStub();	//for trace linking, added by zhengjuyu

						void endOfBlock();
						inline XTInt32 addTBlockExit(XTInt32 why, XTMemAddr next, XTInt32 exitOffset, VInst *inst);
						void encodeExits();


						// =========================================================
						//	    Encoding Related

						XTMemAddr inst_buf;	// instruction buffer
						XTMemAddr p_inst_buf;	// pointer to instruction buffer
						VInst *inst;	// current to-be-encoded virtual instruction

      // the loopAddr and labelAddr are used for Loop instruction
      XTMemAddr loopAddr[2];
      XTMemAddr labelAddr[2];

						void encodeGET();
						void encodePUT();
						void encodeLD();
						void encodeST();
						void encodeLI();
						void encodeMOV();
						void encodeSEXT();
						void encodeZEXT();
						void encodeADD();
						void encodeSUB();
						void encodeADDI();
						void encodeSUBI();
						void encodeAND();
						void encodeXOR();
						void encodeOR();
						void encodeNOT();
						void encodeMUL();
						void encodeMULU();
						void encodeDIV();
						void encodeDIVU();
						void encodeSLL();
						void encodeSLLV();
						void encodeSRL();
						void encodeSRLV();
						void encodeSRA();
						void encodeSRAV();
						void encodeCMP();
						void encodeJMP();
						void encodeBRANCH();
						void encodeSYSCALL();
						void encodeSBREAK();
      
      /*
       * The following are newly introduced VInsts in ia32 front end.
      */
      void encodeUSE();
      void encodeBSF();
      void encodeBSR();
      void encodeDIVU64();
      // LOOP and LABEL
      void encodeLOOP();
      void encodeLOOPN();
      void encodeLABEL();
      

						void encodeFPUTS();
						void encodeFGETS();
						void encodeFPUTD();
						void encodeFGETD();

						void encodeFLD();
						void encodeFST();
						void encodeFMOV();

						void encodeFADDS();
						void encodeFADDD();
						void encodeFSUBS();
						void encodeFSUBD();
						void encodeFMULS();
						void encodeFMULD();
						void encodeFDIVS();
						void encodeFDIVD();
						void encodeFNEGS();
						void encodeFNEGD();
						void encodeFABSS();
						void encodeFABSD();
						void encodeFSQRTS();
						void encodeFSQRTD();
						void encodeFCMPS();
						void encodeFCMPD();

						void encodeFCONV();
						void encodeFINCSTP();
						void encodeCALL();

      
      /*
       * The following are newly introduced float VInsts in ia32 front end.
      */
      void encodeFYL2X();
      void encodeFYL2XP1();
      void encodeFLDL2E();
      void encodeFLDLG2();
      void encodeFLDLN2();
      void encodeFCOS();
      void encodeFPTAN();
      void encodeFSIN();
      void encodeFCHS();
      void encodeFSCALE();
      void encodeF2XM1();
      void encodeFXAM();
      void encodeFRNDINT();

						XTInt32 *allocFpWord(XTInt32);
						XTInt64 *allocFpDword(XTInt64);

						XTInt32 call_stack[CACHE_SIZE];  // 1k words
						XTInt32 fp_word_cache[CACHE_SIZE];
						XTInt64 fp_dword_cache[CACHE_SIZE];
						XTInt32 fp_word_count;
						XTInt32 fp_dword_count;

      // Variables for encoding LOOP, LABEL pairs
      /*
      Word labelAddr[2];
      Word loopAddr[2];
      */
		};
}

#endif
